package com.isoft.illustrationsdraw.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.isoft.illustrationsdraw.brief.BriefIllustrationInfo;
import com.isoft.illustrationsdraw.brief.BriefUserInfo;
import com.isoft.illustrationsdraw.dto.CommentDTO;
import com.isoft.illustrationsdraw.entity.Comment;
import com.isoft.illustrationsdraw.entity.Follow;
import com.isoft.illustrationsdraw.entity.Illustration;
import com.isoft.illustrationsdraw.entity.IllustrationCollection;
import com.isoft.illustrationsdraw.entity.IllustrationTag;
import com.isoft.illustrationsdraw.entity.LikeIllustration;
import com.isoft.illustrationsdraw.entity.User;
import com.isoft.illustrationsdraw.service.CommentService;
import com.isoft.illustrationsdraw.service.FileService;
import com.isoft.illustrationsdraw.service.IllustrationCollectionService;
import com.isoft.illustrationsdraw.service.IllustrationService;
import com.isoft.illustrationsdraw.service.IllustrationTagService;
import com.isoft.illustrationsdraw.service.LikeIllustrationService;
import com.isoft.illustrationsdraw.service.LikeTagService;
import com.isoft.illustrationsdraw.service.UserDTOService;
import com.isoft.illustrationsdraw.service.UserService;
import com.isoft.illustrationsdraw.mapper.FollowMapper;
import com.isoft.illustrationsdraw.mapper.IllustrationMapper;

import com.isoft.illustrationsdraw.service.FollowService;
import com.isoft.illustrationsdraw.mapper.LikeIllustrationMapper;



@Service
public class UserDTOServiceImpl implements UserDTOService{

    private final UserService userService;
    private final FileService fileService;
    private final IllustrationMapper illustrationMapper;
    private final IllustrationCollectionService illustrationCollectionService;
    private final LikeIllustrationMapper likeIllustrationMapper; 
    private final IllustrationService illustrationService;
    private final FollowMapper followMapper;
    private final FollowService followService;
    private final LikeIllustrationService likeIllustrationService;
    private final CommentService commentService;
    private final IllustrationTagService illustrationTagService;
    private final LikeTagService likeTagService;

    public UserDTOServiceImpl(LikeTagService likeTagService, IllustrationTagService illustrationTagService, UserService userService, FileService fileService, IllustrationMapper illustrationMapper, IllustrationCollectionService illustrationCollectionService, LikeIllustrationMapper likeIllustrationMapper, IllustrationService illustrationService, FollowMapper followMapper, FollowService followService, LikeIllustrationServiceImpl likeIllustrationService, CommentService commentService) 
    {
        this.commentService = commentService;
        this.fileService = fileService;
        this.userService = userService;
        this.illustrationMapper =  illustrationMapper;
        this.illustrationCollectionService = illustrationCollectionService;
        this.likeIllustrationMapper = likeIllustrationMapper;
        this.illustrationService = illustrationService;
        this.followMapper = followMapper;
        this.followService = followService;
        this.likeIllustrationService = likeIllustrationService;
        this.illustrationTagService = illustrationTagService;
        this.likeTagService = likeTagService;
    }
    
    @Override
    public BriefUserInfo getBriefUserInfoById(Long id) {

        User userDetail = userService.getById(id);
        if (userDetail == null) {
            return null;
        }
        String profileImgPath = userDetail.getProfileImg();
        if (profileImgPath != null) {
            profileImgPath = fileService.convertToOnlinePath(profileImgPath);
        }

        BriefUserInfo user = new BriefUserInfo(id, userDetail.getNickname(), profileImgPath);
        return user;
    }

        // 提取公共方法
    private List<BriefIllustrationInfo> convertToBriefIllustrationInfo(Long userId, List<?> workList, boolean isLikeQuery) {
        List<IllustrationCollection> collections = new ArrayList<>();
        List<Illustration> illustrations = new ArrayList<>();
        
        for (var work : workList) {
            Long illustrationId = isLikeQuery ? ((LikeIllustration) work).getIllustrationId() : ((Illustration) work).getId();
            collections.add(illustrationCollectionService.getCollectionByIllustrationId(illustrationId).get(0));
            illustrations.add(illustrationService.getById(illustrationId));
        }

        List<BriefIllustrationInfo> result = new ArrayList<>();
        for (int i = 0; i < collections.size(); i++) {
            User author = userService.getById(illustrations.get(i).getAuthorId());
            boolean isLiked = likeIllustrationService.findLikeIllustration(userId, illustrations.get(i).getId()) == null ? false : true;
            result.add(new BriefIllustrationInfo(
                illustrations.get(i).getId(), 
                illustrations.get(i).getTitle(),
                fileService.convertToOnlinePath(collections.get(i).getImageUrl()),
                new BriefUserInfo(author.getId(), author.getNickname(), author.getProfileImg() == null ? null : fileService.convertToOnlinePath(author.getProfileImg())),
                isLiked
            ));
        }

        return result;
    }

    @Override
    public List<BriefIllustrationInfo> getUserWorks(Long userId, Long authorId, Integer page, String authorName) {
        if (authorId == null && authorName == null) {
            return null;
        }
        if (authorId != null && authorName == null) {
            return getUserWorksById(userId, authorId, page);
        }
        if (authorId == null && authorName != null) {
            return getUserWorksByName(userId, authorName, page);

        }
        return null;
    }

    private List<BriefIllustrationInfo> getUserWorksById(Long userId, Long authorId, Integer page) {
        Page<Illustration> illustrationPage = new Page<>(page, 20);
        QueryWrapper<Illustration> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("author_id", authorId);
        var workList = illustrationMapper.selectPage(illustrationPage, queryWrapper).getRecords();
        
        return convertToBriefIllustrationInfo(userId, workList, false);
    }

    private List<BriefIllustrationInfo> getUserWorksByName(Long userId, String authorName, Integer page) {
        Page<Illustration> illustrationPage = new Page<>(page, 20);
        var workList = illustrationMapper.selectIllustrationsByAuthorName(illustrationPage, authorName).getRecords();
        return convertToBriefIllustrationInfo(userId, workList, false); 
    }

    @Override
    public List<BriefIllustrationInfo> getUserLikes(Long userId, Long targerUserId, Integer page) {
        Page<LikeIllustration> likeIllustrationPage = new Page<>(page, 20);
        QueryWrapper<LikeIllustration> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", targerUserId);
        var workList = likeIllustrationMapper.selectPage(likeIllustrationPage, queryWrapper).getRecords();

        return convertToBriefIllustrationInfo(userId, workList, true);
    }

    @Override
    public List<BriefUserInfo> getUserFans(Long id, Integer page) {
        Page<Follow> followPage = new Page<>(page, 20);
        QueryWrapper<Follow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("followed_id", id);
        var workList = followMapper.selectPage(followPage, queryWrapper).getRecords();
        var result = new ArrayList<BriefUserInfo>();
        for (var fan : workList) {
            var fanInfo = userService.getById(fan.getFollowerId());
            result.add(new BriefUserInfo(fanInfo.getId(), fanInfo.getNickname(), fanInfo.getProfileImg() == null ? null : fileService.convertToOnlinePath(fanInfo.getProfileImg())));
        }
        return result;
    }

    @Override
    public List<BriefUserInfo> getFollowedByUser(Long id, Integer page) {
        Page<Follow> followPage = new Page<>(page, 20);
        QueryWrapper<Follow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("follower_id", id);
        var workList = followMapper.selectPage(followPage, queryWrapper).getRecords();
        var result = new ArrayList<BriefUserInfo>();
        for (var followed : workList) {
            var userInfo = userService.getById(followed.getFollowedId());
            result.add(new BriefUserInfo(userInfo.getId(), userInfo.getNickname(), userInfo.getProfileImg() == null ? null : fileService.convertToOnlinePath(userInfo.getProfileImg())));
        }
        return result;
    }

    @Override
    public boolean addFanForUser(Follow newFollowInfo) {
        return followService.save(newFollowInfo);
    }

    @Override
    @Transactional
    public boolean addLikeForUser(LikeIllustration newLike) {
        // 更新 illustration 表的 likes_count 字段，增加 1
        LambdaUpdateWrapper<Illustration> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Illustration::getId, newLike.getIllustrationId())
                     .setSql("likes_count = likes_count + 1");

        boolean updated = illustrationService.update(null, updateWrapper);
        if (!updated) {
            return false; // 如果更新失败，返回 false
        }

        // 保存新的 LikeIllustration 记录
        return likeIllustrationService.save(newLike);
    }

    @Override
    public boolean removeFanForUser(Follow newFollowInfo) {
        return followService.removeById(followService.findFollow(newFollowInfo).getId());
    }

    @Override
    @Transactional
    public boolean removeLikeForUser(LikeIllustration newLike) {

        // 更新 illustration 表的 likes_count 字段，增加 1
        LambdaUpdateWrapper<Illustration> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Illustration::getId, newLike.getIllustrationId())
                        .setSql("likes_count = likes_count - 1");

        boolean updated = illustrationService.update(null, updateWrapper);
        if (!updated) {
            return false; // 如果更新失败，返回 false
        }
        return likeIllustrationService.removeById(likeIllustrationService.findLikeIllustration(newLike.getUserId(), newLike.getIllustrationId()));
    }

    @Override
    public CommentDTO addComment(CommentDTO newCommentDTO) {
        if (checkIfCantPostComment(newCommentDTO.getCommenterId())) {
            return null;
        }

        Comment newComment = new Comment(
            null,
            newCommentDTO.getIllustrationId(),
            newCommentDTO.getCommenterId(),
            newCommentDTO.getContent(),
            null // 不设置 createdAt，让数据库生成默认值
        );
        commentService.save(newComment);
    
        // 根据主键查询插入后的完整数据
        newComment = commentService.getById(newComment.getId());
    
        // 将新数据更新到 DTO
        newCommentDTO.setCommentId(newComment.getId());
        newCommentDTO.setCreatedAt(newComment.getCreatedAt());
    
        // 获取用户信息并设置
        var commenter = userService.getById(newComment.getUserId());
        newCommentDTO.setProfileImgUrl(commenter.getProfileImg() == null ? null : fileService.convertToOnlinePath(commenter.getProfileImg()));
        newCommentDTO.setNickname(commenter.getNickname());
    
        return newCommentDTO;
    }
    
    private boolean checkIfCantPostComment(Long userId) {
        return userService.getById(userId).getIsBanned() == 1 ? true : false;
    }
    @Override
    public List<BriefIllustrationInfo> getRecommandIllustrationByIllustrationId(Long userId, Long sourceIllustrationId) {
        // 调试信息：检查 sourceIllustrationId 是否为 null
        if (sourceIllustrationId == null) {
            System.err.println("Source Illustration ID is null.");
            return new ArrayList<>();
        }
    
        // 获取源插图的标签列表
        var tempSourceTagList = illustrationTagService.getTagsByIllustrationId(sourceIllustrationId);
        List<Long> sourceTagList = new ArrayList<>();
        for (var i : tempSourceTagList) {
            sourceTagList.add(i.getTagId());
        }
    
        // 调试信息：输出源标签列表
        // System.out.println("Source tag list: " + sourceTagList);
    
        // 获取随机插图
        Random random = new Random();
        List<Illustration> targetList = illustrationService.getRandomIllustration(random.nextInt(3) + 1, 20);
        // System.out.println("Randomly selected illustrations: " + targetList);
    
        // 初始化临时标签列表
        List<List<IllustrationTag>> tempTagList = new ArrayList<>();
        List<List<Long>> tagList = new ArrayList<>();
        for (var i : targetList) {
            var tags = illustrationTagService.getTagsByIllustrationId(i.getId());
            tempTagList.add(tags);
            // System.out.println("Tags for illustration ID " + i.getId() + ": " + tags);
        }
    
        // 填充标签ID列表
        for (int i = 0; i < tempTagList.size(); ++i) {
            // 确保 tagList 有对应的子列表
            if (tagList.size() <= i) {
                tagList.add(new ArrayList<>());
            }
    
            for (int j = 0; j < tempTagList.get(i).size(); ++j) {
                tagList.get(i).add(tempTagList.get(i).get(j).getTagId());
            }
            // System.out.println("Tag IDs for illustration ID " + targetList.get(i).getId() + ": " + tagList.get(i));
        }
    
        // 调试信息：检查排序前的目标列表
        // System.out.println("Target list before sorting: " + targetList);
        // System.out.println("Tag list before sorting: " + tagList);
    
        // 按 Jaccard 相似性排序
        sortByJaccardSimilarity(targetList, tagList, sourceTagList);
    
        // 调试信息：检查排序后的目标列表
        // System.out.println("Target list after sorting: " + targetList);
    
        // 转换为简要插图信息并返回
        return convertToBriefIllustrationInfo(userId, targetList, false);
    }
    

    @Override
    public List<BriefIllustrationInfo> getRecommandIllustrationByUserId(Long userId) {
        var tempSourceTagList = likeTagService.getLikeTagsByUser(userId);
        List<Long> sourceTagList = new ArrayList<>();
        for (var i : tempSourceTagList) {
            sourceTagList.add(i.getTagId());
        }

        Random random = new Random();
        List<Illustration> targetList = illustrationService.getRandomIllustration(random.nextInt(3) + 1, 20);
        List<List<IllustrationTag>> tempTagList = new ArrayList<>();
        List<List<Long>> tagList = new ArrayList<>();
        for (var i : targetList) {
            tempTagList.add(illustrationTagService.getTagsByIllustrationId(i.getId()));
        }

        for (int i = 0; i < tempTagList.size(); ++i) {
            for (int j = 0; j < tempTagList.get(i).size(); ++j) {
                tagList.get(i).add(tempTagList.get(i).get(j).getTagId());
            }
        }

        sortByJaccardSimilarity(targetList, tagList, sourceTagList);
        return convertToBriefIllustrationInfo(userId, targetList, false);
    }


    private void sortByJaccardSimilarity(List<Illustration> targetList, List<List<Long>> tagList, List<Long> sourceTagList) {
        // 将源插画的标签ID列表转为集合
        Set<Long> sourceTagIds = new HashSet<>(sourceTagList);
        // 创建一个映射，用于存储插画与其相似度的对应关系
        Map<Illustration, Double> similarityMap = new HashMap<>();
        for (int i = 0; i < targetList.size(); i++) {
            // 将目标插画的标签ID列表转为集合
            Set<Long> targetTagIds = new HashSet<>(tagList.get(i));
            // 计算杰卡德相似度
            double similarity = calculateJaccardSimilarity(sourceTagIds, targetTagIds);
            // 将相似度与插画对应存储
            similarityMap.put(targetList.get(i), similarity);
        }
        // 按相似度降序排序 targetList
        targetList.sort((a, b) -> Double.compare(similarityMap.get(b), similarityMap.get(a)));
    }

    private double calculateJaccardSimilarity(Set<Long> set1, Set<Long> set2) {
        if (set1.isEmpty() && set2.isEmpty()) {
            return 1.0; // 两个集合均为空，相似度为1
        }
        // 计算交集和并集
        Set<Long> intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        Set<Long> union = new HashSet<>(set1);
        union.addAll(set2);
        // 返回杰卡德相似度
        return (double) intersection.size() / union.size();
    }
}
